component
<template>
    <!-- <div class="left"> -->
    <nav class="first-nav">
        <div class="first-nav__logo">
            <el-popover popper-class="first-poper" :width="200" trigger="hover">
                <template #default>
                    <div class="first-nav__wrap flexs" @click.stop="clickGk">
                        <p>返回首页</p>
                    </div>
                    <div class="first-nav__wrap flexs" @click.stop="ChangePass">
                        <p>修改密码</p>
                    </div>
                    <div class="first-nav__wrap flexs" @click.stop="signOut">
                        <p>退出登录</p>
                        <el-icon>
                            <switch-button />
                        </el-icon>
                    </div>
                </template>
                <template #reference>
                    <el-image class="logo-img" :src="logo"></el-image>
                </template>
            </el-popover>
        </div>
        <!-- showStyle为true时 -->
        <ul class="first-nav__ul">
            <li
                class="first-nav__li"
                v-for="(first, index) in menuTree"
                :key="index"
                :class="{
                    'nav-active': activeFirstNavIndex === index,
                    'nav-hover': hoverFirstNavIndex === index,
                }"
            >
                <!-- 一级菜单 -->
                <div
                    class="first-nav__li-item"
                    @click.stop="clickOneNav(first, index)"
                >
                    <!-- 一级菜单图标 -->
                    <el-icon v-if="first[MENU_KEY_CONFIG.ICON]">
                        <component :is="first[MENU_KEY_CONFIG.ICON]" />
                    </el-icon>
                    <!-- 一级菜单名称 -->
                    <span>{{ first[MENU_KEY_CONFIG.NAME] }}</span>
                </div>
            </li>
        </ul>
        <!-- 子菜单 -->
        <div class="sub-menu" v-if="showSubMenu">
            <!-- 副标题 -->
            <h3 class="second-nav__h3">{{ subTitle }}</h3>
            <!-- 子菜单 -->
            <div class="sub-ul" @click.stop>
                <el-menu
                    :default-active="defaultActive"
                    router
                    :default-openeds="defaultOpeneds"
                    @select="selectMenu"
                    class="menu-box"
                >
                    <menu-items
                        v-for="route in menuTree[activeFirstNavIndex][
                            MENU_KEY_CONFIG.CHILDREN
                        ]"
                        :key="route[MENU_KEY_CONFIG.PATH]"
                        :item="route"
                    ></menu-items>
                </el-menu>
            </div>
        </div>
    </nav>
    <!-- </div> -->
</template>

<script setup>
import { inject, ref, reactive, computed, onMounted, watch, toRefs } from "vue";
import { useRouter, useRoute } from "vue-router";
import { useUserStore } from "@stores/user";
import logo from "@images/logo.png";
import MenuItems from "./MenuItems.vue";
import { MENU_KEY_CONFIG } from "@/assets/common/config.js";
import { ElMessageBox } from "element-plus";
import { userLogout } from "@/assets/common/utils";

const userStore = useUserStore();
const router = useRouter();
const route = useRoute();
const $message = inject("$message");

const data = reactive({
    hoverFirstNavIndex: null,
});

const { hoverFirstNavIndex } = toRefs(data);

// 菜单树
const menuTree = computed(() => userStore.menuTree);
// 所有有效菜单(path不为空) 一维数组结构
const allMenuArr = computed(() => recursionArrs(menuTree.value));
// 默认激活一级菜单path
const defaultActive = computed(() => route.path);
// 默认展开的二级菜单path
const defaultOpeneds = computed(() => userStore.defaultOpeneds);
// 当前激活的一级菜单索引
const activeFirstNavIndex = computed(() => userStore.activeFirstNavIndex);
// 副标题
const subTitle = computed(() => userStore.subTitle);
// 是否展示子菜单
const showSubMenu = computed(() => userStore.showSubMenu);

onMounted(() => {});

// 递归多维数组对象，然后组合成只包含path，id两个字段的一维数组对象
function recursionArrs(menuTreeList, menuList = []) {
    for (let item of menuTreeList) {
        if (item[MENU_KEY_CONFIG.PATH]) {
            menuList.push({
                path: item[MENU_KEY_CONFIG.PATH],
                id: item[MENU_KEY_CONFIG.UNIQUE],
            });
        }
        if (item[MENU_KEY_CONFIG.CHILDREN]?.length) {
            recursionArrs(item[MENU_KEY_CONFIG.CHILDREN], menuList);
        }
    }
    return menuList;
}
// 遍历获取菜单ID，用于展开二级菜单
function getDefaultOpeneds(arrs) {
    let ids = arrs.map((item) => item.id);
    ids = Array.from(new Set(ids));
    return ids.map(String);
}

const selectMenu = (index, path) => {
    if (data.hoverFirstNavIndex != null) {
        userStore.setCurFirstNavIndex(data.hoverFirstNavIndex);
    }
    userStore.initKeepAlive();
};

// 一级导航鼠标移入
const mouseOneEnter = (item, index) => {
    data.hoverFirstNavIndex = index;

    const menu = menuTree.value[index];
    if (menu[MENU_KEY_CONFIG.CHILDREN]?.length) {
        userStore.setSubTitle(index);
        userStore.activeSubMenu();
    } else {
        userStore.hiddenSubMenu();
    }
};

// 一级导航鼠标移出
const mouseOneLeave = (item, index) => {
    data.hoverFirstNavIndex = null;
    if (
        activeFirstNavIndex.value < 0 ||
        !menuTree.value[activeFirstNavIndex.value][MENU_KEY_CONFIG.CHILDREN]
            ?.length
    ) {
        userStore.hiddenSubMenu();
    } else {
        userStore.activeSubMenu();
    }
};

// 点击一级菜单
const clickOneNav = (item, index) => {
    userStore.setCurFirstNavIndex(index);
    const menu = menuTree.value[index];
    if (menu[MENU_KEY_CONFIG.CHILDREN]?.length) {
        userStore.setSubTitle(index);
        userStore.activeSubMenu();
    } else {
        userStore.hiddenSubMenu();
    }
    userStore.initKeepAlive();
    router.push({
        path: "/" + item[MENU_KEY_CONFIG.PATH],
    });
};

// 返回概况
const clickGk = () => {
    userStore.clearCurFirstNavIndex();
    userStore.setCurFirstNavIndex(0);
    userStore.initKeepAlive();
    router.replace("/Home");
};

// 退出
const signOut = () => {
    ElMessageBox.confirm("确定退出当前账号吗？", "温馨提示", {
        type: "warning",
        confirmButtonText: "确定",
        cancelButtonText: "取消",
    })
        .then(() => {
            userLogout();
            router.replace("/");
        })
        .catch(() => {});
};

// 修改密码
const ChangePass = () => {
    userStore.clearCurFirstNavIndex();
    router.replace("/ChangePass");
};
</script>

<style lang="less" scoped>
.second-nav__h3 {
    flex: 0 0 @height-mdl;
    padding-left: 18px;
    text-align: left;
    height: @height-mdl;
    box-sizing: border-box;
    border-bottom: 1px solid #ebedf0;
    font-size: @font-size-md;
    color: @gray-8;
    line-height: @height-mdl;
    font-weight: 500;
}

.first-nav {
    height: 100%;
    display: flex;
    flex-direction: column;
    overflow: hidden;

    .first-nav__logo {
        display: flex;
        justify-content: center;
        align-items: center;
        margin: 15px 0;

        .logo-img {
            cursor: pointer;
            width: 40px;
            height: 40px;
            overflow: hidden;
        }
    }

    .first-nav__ul {
        overflow-y: scroll;
        scrollbar-width: none;

        &::-webkit-scrollbar {
            width: 0;
            height: 0;
            display: none;
            /* Chrome, Safari, Opera */
        }

        .first-nav__li {
            font-size: @font-size-md;
            height: 40px;
            cursor: pointer;
            font-size: 14px;
            color: #c8c9cc;

            &:hover,
            &.nav-hover {
                color: #fff;
                background: rgba(255, 255, 255, 0.2);

                .sub-menu {
                    z-index: 999;
                    visibility: visible;
                }
            }

            &.nav-active {
                .sub-menu {
                    visibility: visible;
                }

                background: #4b93fa;
                color: #fff;
            }

            // 一级菜单
            .first-nav__li-item {
                display: flex;
                align-items: center;
                justify-content: center;
                height: 100%;

                span {
                    max-width: 48px;
                    overflow: hidden;
                    text-overflow: ellipsis;
                    white-space: nowrap;
                }
            }

            i {
                font-size: 16px;
                margin-right: 6px;
            }
        }
    }

    // 子菜单
    .sub-menu {
        cursor: default;
        position: fixed;
        width: @sub-menu-width;
        height: 100%;
        z-index: 99;
        top: 0;
        left: @first-menu-width;
        overflow: hidden;
        display: flex;
        background: #fff;
        flex-direction: column;
        border-right: @border-gray;
        padding-bottom: @padding-base * 10;

        .sub-ul {
            margin-top: 10px;
            box-sizing: content-box;
            padding-right: @padding-mdl;
            padding-left: 10px;
            width: 100%;
            overflow-x: hidden;
            overflow-y: scroll;

            .menu-box {
                border: 0;

                :deep(.el-sub-menu__title) {
                    padding: 0 !important;
                    height: 40px;
                    margin-bottom: 5px;

                    &:hover {
                        background: none;
                    }
                }

                :deep(.el-menu-item),
                :deep(.el-sub-menu) {
                    line-height: 32px;
                    width: 118px;
                    text-align: left;
                    padding-left: 10px !important;
                    overflow: hidden;
                    min-width: auto;
                    display: inline-block;
                    box-sizing: border-box;
                    color: @gray-8;

                    &:hover {
                        color: @themes !important;
                        background: none;
                    }
                }

                :deep(.el-menu-item) {
                    height: 32px;
                    margin-bottom: @margin-xs;

                    &.is-active {
                        background-color: @gray-3;
                    }
                }

                :deep(.el-sub-menu) {
                    .el-sub-menu__icon-arrow {
                        right: 0;
                    }

                    .el-menu-item {
                        margin-bottom: 0;
                    }
                }
            }
        }
    }
}
</style>

<style lang="less">
// el-popover生成的div不在当前组件之内，甚至不在App.vue组件的div内，他和App.vue组件的div平级，所以需要设置全局style。
.first-poper {
    padding: 6px 0px;
    border: 0;

    .first-nav__wrap {
        cursor: pointer;
        color: #111;
        padding: 12px;
        overflow: hidden;

        &:hover {
            background: rgba(0, 0, 0, 0.05);
        }
    }
}
</style>
